﻿using Dapper_Core.Basic;
using Dapper_Core.BLL.Impl;
using Dapper_Core.Common;
using Dapper_Core.Table;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Quartz;
using Quartz.Impl;
using Quartz.Spi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Dapper_Core.AutoJob
{
    public static class QuartzArtifiService
    {
        #region 项目启动时执行单任务
        public static void StartJob<TJob>() where TJob : IJob
        {
            var scheduler = SchedulerGenerator.GetScheduler();

            var job = JobBuilder.Create<TJob>()
              .WithIdentity("job")
              .Build();

            var trigger1 = TriggerBuilder.Create()
              .WithIdentity("job.trigger")
              .StartNow()
              .WithSimpleSchedule(x => x.WithInterval(TimeSpan.FromSeconds(5)).RepeatForever())
              .ForJob(job)
              .Build();

            scheduler.AddJob(job, true);
            scheduler.ScheduleJob(job, trigger1);
            scheduler.Start();
        }
        #endregion

        #region 项目启动时执行多任务
        public static void StartJobs<TJob>() where TJob : IJob
        {
            //无论在哪里只要对同一个scheduler绑定的任务和触发器，都会被统一调度
            var scheduler = SchedulerGenerator.GetScheduler();
            //scheduler可以先启动也可以后启动，scheduler启动后再绑定的任务和触发器也能执行
            scheduler.Start();

            #region 脱离数据库执行定时任务
            #region 创建job方法1
            //IJobDetail job = JobBuilder.Create<TJob>()
            //    .WithIdentity("jobs")
            //    .Build();
            #endregion

            #region 创建job方法2
            //var jobBuilderType = typeof(JobBuilder);
            //var method = jobBuilderType.GetMethods().FirstOrDefault(x => x.Name.Equals("Create", StringComparison.OrdinalIgnoreCase) && x.IsGenericMethod && x.GetParameters().Length == 0)
            //    ?.MakeGenericMethod(Type.GetType("Dapper_Core.AutoJob.QuartzJob,Dapper_Core.AutoJob"));
            //var jobBuilder = (JobBuilder)method.Invoke(null, null);
            //IJobDetail job = jobBuilder.WithIdentity("jobs").Build();
            #endregion

            //var trigger1 = TriggerBuilder.Create()
            //  .WithIdentity("job.trigger1")
            //  .WithSimpleSchedule(x => x.WithInterval(TimeSpan.FromSeconds(5)).RepeatForever())
            //  .StartNow()
            //  .Build();

            //var trigger2 = TriggerBuilder.Create()
            //  .WithIdentity("job.trigger2")
            //  .WithSimpleSchedule(x => x.WithInterval(TimeSpan.FromSeconds(11)).RepeatForever())
            //  .StartNow()
            //  .Build();

            //var dictionary = new Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>>
            //{
            //  {job, new HashSet<ITrigger> {trigger1, trigger2}}
            //};
            //scheduler.ScheduleJobs(dictionary, true); 
            #endregion

            #region 根据数据库执行定时任务
            List<Sys_Job> jobList = new Sys_JobBusiness().GetList(job => job.Status == 1).ToList();
            if (!jobList.HasData()) return;
            jobList = jobList.Where(job => job.JobType == 0).ToList();
            foreach (Sys_Job item in jobList)
            {
                Type type = Type.GetType(item.JobCall);
                if (type == null) continue;
                var jobBuilderType = typeof(JobBuilder);
                var method = jobBuilderType.GetMethods().FirstOrDefault(x => x.Name.Equals("Create", StringComparison.OrdinalIgnoreCase) && x.IsGenericMethod && x.GetParameters().Length == 0)
                    ?.MakeGenericMethod(type);
                var jobBuilder = (JobBuilder)method.Invoke(null, null);
                IJobDetail job = jobBuilder.WithIdentity(item.JobId).Build();

                var trigger = TriggerBuilder.Create()
                  .WithIdentity(item.JobId)
                  .WithCronSchedule(item.Cron)
                  .StartNow()
                  .Build();

                scheduler.AddJob(job, true);
                scheduler.ScheduleJob(job, trigger);
            }
            #endregion
        }
        #endregion

        /// <summary>
        /// 后台管理定时任务时动态启动/停止任务
        /// </summary>
        /// <param name="sysJob"></param>
        public static void HandleJob(Sys_Job sysJob)
        {
            if (sysJob.Status == 0)
            {
                StopJob(sysJob.JobId);
            }
            else if (sysJob.Status == 1)
            {
                StopJob(sysJob.JobId);
                StartJob(sysJob);
            }
        }

        /// <summary>
        /// 后台管理定时任务时动态启动任务
        /// </summary>
        /// <param name="job"></param>
        public static void StartJob(Sys_Job sysJob)
        {
            //无论在哪里只要对同一个scheduler绑定的任务和触发器，都会被统一调度
            var scheduler = SchedulerGenerator.GetScheduler();
            if (sysJob.JobType == 0)
            {
                #region 执行本地任务
                Type type = Type.GetType(sysJob.JobCall);
                if (type == null) return;
                var jobBuilderType = typeof(JobBuilder);
                var method = jobBuilderType.GetMethods().FirstOrDefault(x => x.Name.Equals("Create", StringComparison.OrdinalIgnoreCase) && x.IsGenericMethod && x.GetParameters().Length == 0)
                    ?.MakeGenericMethod(type);
                var jobBuilder = (JobBuilder)method.Invoke(null, null);
                IJobDetail job = jobBuilder.WithIdentity(sysJob.JobId).Build();

                var trigger = TriggerBuilder.Create()
                  .WithIdentity(sysJob.JobId)
                  .WithCronSchedule(sysJob.Cron)
                  .StartNow()
                  .Build();

                scheduler.AddJob(job, true);
                scheduler.ScheduleJob(job, trigger);
                #endregion
            }
            else if(sysJob.JobType == 1)
            {
                #region 执行外部接口任务

                #endregion
            }
        }

        /// <summary>
        /// 后台管理定时任务时动态停止任务
        /// </summary>
        /// <param name="jobId">任务Id（支持多个）</param>
        /// <param name="delimiter">分隔符</param>
        public static void StopJob(string jobIds, string delimiter = ",")
        {
            if (jobIds.IsEmpty()) return;
            if (delimiter.IsEmpty()) delimiter = ",";
            string[] jobIdList = jobIds.Split(delimiter, StringSplitOptions.RemoveEmptyEntries);
            if (!jobIdList.HasData()) return;
            foreach (string jobId in jobIdList)
            {
                //无论在哪里只要对同一个scheduler绑定的任务和触发器，都会被统一调度
                var scheduler = SchedulerGenerator.GetScheduler();
                TriggerKey triggerKey = new TriggerKey(jobId);
                // 停止触发器
                scheduler.PauseTrigger(triggerKey);
                // 移除触发器
                scheduler.UnscheduleJob(triggerKey);
                // 删除任务
                scheduler.DeleteJob(new JobKey(jobId));
            }
        }

        #region 配置
        public static void AddQuartz(this IServiceCollection services, params Type[] jobs)
        {
            services.AddSingleton<IJobFactory, QuartzFactory>();
            services.Add(jobs.Select(jobType => new ServiceDescriptor(jobType, jobType, ServiceLifetime.Singleton)));

            services.AddSingleton(provider =>
            {
                var schedulerFactory = new StdSchedulerFactory();
                var scheduler = schedulerFactory.GetScheduler().Result;
                scheduler.JobFactory = provider.GetService<IJobFactory>();
                scheduler.Start();
                return scheduler;
            });
        }
        #endregion
    }
}
